#ifndef CPP11SEMAPHORE_H
#define CPP11SEMAPHORE_H

/*
* author: http://p9as.blogspot.com/2012/06/c11-semaphores.html
* modified by: ilovers
*/

#include <mutex>
#include <condition_variable>

class safe_semaphore {
public:
	safe_semaphore(int value=1): count{value} {}

	void wait(){
		std::unique_lock<std::mutex> lock{ mutex };
        if (count == 0) {
            condition.wait(lock, [&]()->bool{ return count>0; });
        }
        count--;
	}
    bool wait_timeout(int milsec){
        std::unique_lock<std::mutex> lock{ mutex };
        if(condition.wait_for(lock, std::chrono::milliseconds(milsec), [&]()->bool{ return count>0; }))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    void signal(){
        std::lock_guard<std::mutex> lock{mutex};
        condition.notify_one();
        count++;
    }
    void test_wait(){
        std::unique_lock<std::mutex> lock{ mutex };
        if (count == 0) {
            condition.wait(lock, [&]()->bool{ return count>0; });
        }
    }
    bool test(){
        std::lock_guard<std::mutex> lock{mutex};
        if(count == 0)
            return false;
        else
            return true;
    }
    bool try_lock(){
        std::lock_guard<std::mutex> lock{mutex};
        if(count == 0)
            return false;
        else
        {
            count--;
            return true;
        }
    }

    int count;

private:
    std::mutex mutex;
    std::condition_variable condition;
};

#endif // CPP11SEMAPHORE_H

